#!/usr/bin/env python
#-*- coding: utf-8 -*-

import socket
from base64 import b64encode
from os import path
from sqlite3 import dbapi2 as sqlite
from os import sep
from os import makedirs

#Protocolo
AUTENTICAR = "A"
VOTAR = "V"
IMAGEM = "I"
PARTIDO = "P"
CANDIDATO ='C'
ERROR = "E"
OK = 'OK'
DIVISOR='|'

#Constantes
HOST='127.0.0.1'
PORTA = 2727
TAM = 1024 # Tamanho recebido em bytes
CONEXOES = 2

TEMP='arquivos' 
BANCO=TEMP+sep+'servidor.db'

BRANCO='-1'


#
#   TODO Colocar com valor no dicionário o ip do cliente
#
def criar_banco_dados(caminho):
    try:
        if not path.exists(caminho):
            conn = sqlite.connect(caminho)
            cursor = conn.cursor()
            cursor.execute('CREATE TABLE Eleitores(id INTEGER primary key,nome text NOT NULL ,cpf text NOT NULL UNIQUE,voto text)')
            cursor.execute('CREATE TABLE Partidos(id INTEGER primary key,nome text NOT NULL ,numero text NOT NULL UNIQUE)')
            cursor.execute('CREATE TABLE Politicos(id INTEGER primary key,nome text NOT NULL,numero text NOT NULL UNIQUE,votos integer DEFAULT 0)')
            
            cursor.execute('INSERT INTO Politicos(nome,numero) VALUES(?,?)',('Branco','-1'))
            cursor.execute('INSERT INTO Politicos(nome,numero) VALUES(?,?)',('Nulo','-2'))
                
            cursor.close()
            conn.commit()
        else:
            conn = sqlite.connect(BANCO)
        return conn
    except:
        raise Exception('Erro na conexao do banco de dados')

class Server(object):
    def __init__(self,host,port):
        
        self.sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
        self.sock.bind((host,port))
        self.sock.listen(CONEXOES) #Permir n conexoes
        
        print "Server runing in", host,port      
        self.conexoes = {} # Chaves e ligada ao cpf
        
        if not path.isdir(TEMP): # Se nao existe a pasta cria
            makedirs(TEMP)
            
        self.conn = criar_banco_dados(BANCO)
    
   
    def informar_cargo(self,cargo):
        self.cargo=cargo
   
    #socket    


    def autenticar(self,cpf):
        #ENVIAR o CARGO da ELEICAO
        #Se tiver no banco de dados
        cursor = self.conn.cursor()
        cursor.execute('SELECT nome,voto FROM Eleitores WHERE cpf=?',(cpf,))
        
        try:
            eleitor,voto = cursor.next()
            cursor.close()
            
            if not voto:
                if eleitor:
                    print 'ELEITOR ENCONTRADO:',eleitor
                    self.conexoes[cpf] = b64encode(cpf)
                    tupla = (OK,self.cargo)
                else:
                    print 'ELEITOR NÃO ENCONTRADO'
                    tupla = (ERROR,'Eleitor não cadastrado')
            else:
                print 'ELEITOR JÁ VOTOU!'
                tupla = (ERROR,'Eleitor já votou')
        except:
            cursor.close()
            print 'ELEITOR NÃO ENCONTRADO'
            tupla = (ERROR,'Eleitor não cadastrado')
            
        return tupla
            
    def esta_autenticado(self,cpf):
        
        if self.conexoes.has_key(cpf):
            bool = True
        else:
            bool = False
        return bool
    
    
    def votar(self,chave,numero):
        
        if self.esta_autenticado(chave):
            cursor = self.conn.cursor()
            cursor.execute('SELECT voto FROM Eleitores WHERE cpf=?',(chave,))
            voto = cursor.fetchone()
            print "VOTO:",voto
            if not voto[0]:
                
                #Inserir voto no eleitor
                cursor.execute('UPDATE Eleitores SET voto=? WHERE cpf=?',(numero,chave))
                
                #Inserir voto no candidato
                if numero==BRANCO:
                    cursor.execute('UPDATE Politicos SET votos=votos+1 where nome="Branco"',)
                else:
                    
                    if cursor.execute('SELECT * FROM Politicos WHERE numero=?',(numero,)).fetchone():
                        cursor.execute('UPDATE Politicos SET votos=votos+1 WHERE numero=?',(numero,))
                    else:
                        cursor.execute('UPDATE Politicos SET votos=votos+1 WHERE nome="Nulo"')
                    
                    
                tupla = (OK,'Voto computado.')
                del(self.conexoes[chave])
            else:
                tupla = (ERROR,'O Eleitor já votou.')
            
        else:
            tupla = (ERROR,'Eleitor não autenticado')
        
        self.conn.commit()
        cursor.close()
        
        return tupla
    
    def partido_politico(self,numero):
        cursor = self.conn.cursor()
        cursor.execute('SELECT nome FROM Partidos WHERE numero=?',(numero,))
        partido = cursor.fetchone()
        
        if partido:
            print 'PESQUISA NO SERVIDOR:',partido[0]
            tupla = (OK,partido[0])
        else:
            tupla = (ERROR,'Partido desconhecido!')
        
        cursor.close()    
        return tupla
    
    def nome_candidato(self,numero):
        cursor = self.conn.cursor()
        cursor.execute('SELECT nome FROM Politicos WHERE numero=?',(numero,))
        nome = cursor.fetchone()
        if nome:
            
            tupla = (OK,nome[0])
            print 'PESQUISA NO SERVIDOR:',tupla[1]
        else:
            tupla = (ERROR,'Candidato desconhecido')
        cursor.close()
        
        return tupla
    
    def imagem(self,numero):
        imagem = TEMP+sep+numero+'.jpg'
        print 'PEDIDO DE IMAGEM AO SERVIDOR'
        if path.exists(imagem):
            arq = open(imagem,'rb')
            buffer = arq.read()
            tupla = (OK,buffer)
        else: 
            tupla= (ERROR,"Imagem não encontrada")
        
        return tupla
            
    
    def run(self):
        """
        Colocar o servidor para rodar
        """
        protocolo={         #dicionario com os respectivos metodos
                    AUTENTICAR: self.autenticar,
                    PARTIDO: self.partido_politico,
                    CANDIDATO: self.nome_candidato,
                    IMAGEM: self.imagem,          
                   }
        
        while True:
            
            conn,ip = self.sock.accept()            
            
            msg = conn.recv(TAM) # Receber informacoes
            if msg:
            
            
                tipo,chave,msg = msg.split('|')
                
                print tipo,msg
                
                
                if tipo==VOTAR:
                    tipoRetorno,msgRetorno = self.votar(chave,msg)
                elif protocolo.has_key(tipo):   # Se o tipo estiver no dicionario
                    tipoRetorno,msgRetorno = protocolo[tipo](msg)  #chama a respectiva funcao com o parametro
                else:                   # Se o tipo for desconhecido manda uma resposta de ERROR
                    tipoRetorno = ERROR     
                    msgRetorno = "Tipo de pedido desconhecido!"
                
                conn.send(tipoRetorno+DIVISOR+msgRetorno)
            conn.close()


class BancoDados(object):
    
    def __init__(self,conexao=BANCO):
        self.conexao=criar_banco_dados(conexao)
      
    def __executar_query(self,query,vars):
        cursor = self.conexao.cursor()
        cursor.execute(query,vars)
        self.conexao.commit()
        lista = cursor.fetchall()
        cursor.close()
        return lista
        
    def todos_eleitores(self,condicao=""):
        return self.__executar_query('SELECT * FROM Eleitores'+condicao,())
    
    def todos_partidos(self,condicao=""):
        return self.__executar_query('SELECT * FROM Partidos'+condicao,())
    
    def todos_politicos(self,condicao=""):
        return self.__executar_query('SELECT * FROM Politicos'+condicao,())
    
    def inserir_partido(self,nome,numero):
        self.__executar_query('INSERT INTO Partidos(nome,numero) VALUES(?,?)',(nome,numero))
        
    def inserir_politico(self,nome,numero):
        self.__executar_query('INSERT INTO Politicos(nome,numero) VALUES(?,?)',(nome,numero))
        
    def inserir_eleitor(self,nome,cpf):    
        self.__executar_query('INSERT INTO Eleitores(nome,cpf) VALUES(?,?)',(nome,cpf))
    
    def buscar_eleitor(self,cpf):
        return self.__executar_query('Select * FROM Eleitores WHERE cpf=?',(cpf,))
    
    def buscar_partido(self,numero):
        return self.__executar_query('Select * FROM Partidos WHERE numero=?',(numero,))
    
    def buscar_politico(self,numero):
        return self.__executar_query('Select * FROM Politicos WHERE numero=?',(numero,))
        
if __name__ == '__main__':
    
    servidor = Server('localhost',PORTA)
    servidor.informar_cargo('Presidente')
    #cursor = servidor.conn.cursor()
    #cursor.execute('INSERT INTO Eleitores(nome,cpf) VALUES ("Rodrigo Lira","08201540409")')
    #cursor.execute('INSERT INTO Eleitores(nome,cpf) VALUES ("Rai Cesar","44444444444")')
    #cursor.execute('INSERT INTO Politicos(nome,numero) VALUES ("Dilma","13")')
    #cursor.execute('INSERT INTO Partidos(nome,numero) VALUES ("PT","13")')
    servidor.run()
        
